Configure, boot, store and hash the Cartesi machine through the @cartesi/machine
N-API bindings, instead of spawning cartesi-machine and
cartesi-machine-stored-hash (falling back to running them inside the SDK docker
image).
machine.ts now translates a cartesi.toml Config into an emulator MachineConfig
directly, mirroring what the cartesi-machine CLI does with its command line:
the boot args it appends to, the init script (splash, flash drive mounts and
chowns, nvram permissions and chowns, environment exports, WORKDIR and USER),
the flash drives with root first so it lands on pmem0, the nvram ranges in
declaration order, and the virtio console setup for an interactive shell.
buildMachineConfig is a pure function, covered by unit tests.
With no SDK image to take the kernel from, images.ts downloads the pinned
cartesi/machine-linux-image release on first use, verifies its checksum and
caches it under XDG_CACHE_HOME. CARTESI_IMAGES_PATH and machine.ram_image still
win.
The run loop can capture the guest console into a file and return it, which is
how a test reads what the machine printed now that there is no child process to
read stdout from.
The emulator moves from 0.20 to 0.21, so machine hashes change. The standalone
binaries are gone: a bun single file executable has no node_modules, and the
addon resolves its platform .node at runtime, so it cannot be embedded.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UTEd5g3mF849BATTstssR3
Contributes to #72.
That issue asks for the external programs the CLI drives to stop being spawned binaries, and notes that "instead of spawning binaries another possibility is to build NodeJS bindings to native code components". This PR takes that route for the emulator.
cartesi-machineexeca, falling back todocker runin the SDK image@cartesi/machinecartesi-machine-stored-hashexeca, falling back todocker runin the SDK image@cartesi/machinexgenext2fsgets the same treatment in #517, stacked on this branch.mksquashfs,cartesi-rollups-cliandcartesi-rollups-nodeare untouched by either, so the remaining work on #72 is the Node Unit's binaries.Note
The branch name still says
xgenext2fs-cartesi-machine— it carried both changes before the split, and GitHub does not allow repointing a PR's head branch. Only the machine commit is here now.What changed
src/machine.ts— the substantial part. The CLI used to handcartesi-machinea command line and let it assemble the machine configuration. It now does that translation itself, transcribed fromcartesi-machine.luav0.21.0:dtb.bootargsfrom the emulator, withmachine.boot_argsappendeddtb.init: the splash, thendev=$(flashdrive <label>)+ mount + chown per non-root drive, thendev=$(nvram <label>)+chmod 0664+ chown per nvram, thenexport K="V",WORKDIR,USER— in the order the old argv producedrootfirst, so it lands on/dev/pmem0regardless of the order drives appear incartesi.toml/dev/uio*device each one gets, sized fromsizeor derived from the backing imageconsole=hvc1andiunrep=1forcartesi shellbuildMachineConfigis a pure function so this is unit-testable without running a machine;src/exec/cartesi-machine.tsholds the run loop (automatic yields acknowledged, console I/O resumed, guest exit code read fromhtif_tohost_data).src/images.ts(new) — with no SDK image to takelinux.binfrom, the defaultram_imageis fetched from the pinnedcartesi/machine-linux-imagev0.21.0 release on first use, verified against its SHA-256 and cached under$XDG_CACHE_HOME/cartesi/images. ACARTESI_IMAGES_PATHdirectory holding the image is used when set, andmachine.ram_imagestill wins over both.Console capture —
bootMachinegrew acaptureOutputoption. There is no child process to readstdoutfrom any more, and the emulator exposes no API to read a captured console back, so it writes to a temporary file that the run reads once it is over. This is what keepstests/integration/machine/nvram.test.tsable to assert on what the guest printed.Breaking
@cartesi/machinelinks against emulator 0.21, the SDK image pins 0.20. Applications need redeploying.cartesi hashandcartesi statusno longer runcartesi-machine-stored-hashin the project's SDK image, so a snapshot stored by an incompatible emulator reads as no hash and has to be rebuilt.getMachineHashlost itssdkoption accordingly, which also drops the now-unusedsdkplumbing throughrun's interactive shell.--append-bootargs="<arg>"with no shell in between, so the quotes ended up in the kernel command line. Building the configuration directly, reproducing that would have meant reproducing a bug.node_modules, and the addon resolves its platform.nodeat runtime — a host-native--compilefails too, so cross-compiling four targets was never going to work. The compile step inbuild.tsand the upload step inrelease.yamlare removed here. The homebrew formula incartesi/homebrew-tapneeds to install from npm rather than the release tarball. Happy to revert this bit and solve distribution differently if you'd rather keep the binaries.Rebased onto the nvram and version-check work
The base moved 61 commits while this sat, and a few of them built directly on the code this replaces, so the update was a port rather than a conflict resolution:
fdfd3c1,81fedfc,a3cfe1f,81e6157,bb31cfe,5fd7421) went in as--nvram=flags. They are nownvrammemory ranges in the machine configuration, with the init lines the emulator's own CLI generates for them. Resolving the conflict without porting this would have silently dropped nvram support.481cc2f,fdd6d93,f48d0a3,c9878d6,5493e17) probedcartesi-machine --version-jsonthrough Docker.requiredVersion,UnsupportedVersionErrorandassertSupportedare kept as they were — they still guard that the linked emulator is in range — whileversion()is now a local lookup, andassertVersion()takes no options. The unit tests for them are kept, anddoctorreports the compiled-in version instead of probing an install.@cartesi/machine@alphamoved from1.0.0-alpha.0to1.0.0-alpha.2, which returns hashes asUint8Arrayrather thanBuffer; those are converted with viem'sbytesToHex.Testing
tests/unit/machine.test.tscovers the configuration translation (mount points, drive ordering, nvram sizing and ordering, nvram init lines, environment precedence, workdir/user, interactive mode,parseMemorySize); the base branch's nvram cases are carried over as assertions on the configuration rather than on argv.nvramranges, that the init script matches the Lua reference, and thatcaptureOutputreturns the guest console.cartesi-machine-stored-hash.test.tskeeps the base branch'sisHashassertion, on the new signature. Its "with the project sdk image" case is gone, since hashing no longer involves an image; the replacement assertsgetMachineHash()resolves the project snapshot.Not verified locally: a successful rollup application boot and the nvram integration tests, which need Docker with riscv64. CI covers those.
🤖 Generated with Claude Code
https://claude.ai/code/session_01UTEd5g3mF849BATTstssR3